/**
 * 2015，thor.com，all rights reserved。
 * 
 * Project：		thor-common
 * Filename：	QueryExecutor.java
 * Created：		2015年3月14日
 * Creator：		thor
 */
package com.jeecg.query.executor;

import java.util.Collection;
import java.util.List;
import java.util.Map;

import org.hibernate.Query;
import org.hibernate.Session;

import com.jeecg.common.Assert;
import com.jeecg.query.QueryExecutor;
import com.jeecg.query.QueryResult;
import com.jeecg.query.SQLSubquery;

/**
 * @author thor
 * 
 */
public class HibernateQueryExecutor implements QueryExecutor {
  private SQLSubquery sql;
  private Session session;

  public HibernateQueryExecutor(Session session, SQLSubquery sql) {
    this.session = session;
    this.sql = sql;
  }

  @Override
  public QueryResult<?> query(int pageNumber, int pageSize) {
    return query(pageNumber, pageSize, Object.class);
  }

  /**
   * 分页查询。
   * 
   * @param pageNumber
   *          页码，起始于0
   * @param pageSize
   *          每页记录数，等于0表示取全部记录。
   * @param resultType
   *          数据类型。
   * @return
   */
  @SuppressWarnings({
      "unchecked", "rawtypes" })
  @Override
  public <T> QueryResult<T> query(int pageNumber, int pageSize, Class<T> resultType) {
    Assert.assertAttributeNotNull(session, "session");
    Assert.assertAttributeNotNull(sql, "sql");
    if (pageNumber < 0) {
      throw new IllegalArgumentException("pageNumber不能小于0");
    }
    if (pageSize < 0) {
      throw new IllegalArgumentException("pageSize不能小于0");
    }

    Query query = session.createQuery(sql.toSQL());
    for (Map.Entry<String, Object> parameter : sql.getParameters().entrySet()) {
      if (parameter.getValue() instanceof Collection) {
        query.setParameterList(parameter.getKey(), (Collection<?>) parameter.getValue());
      } else if (parameter.getValue() instanceof Object[]) {
        query.setParameterList(parameter.getKey(), (Object[]) parameter.getValue());
      } else {
        query.setParameter(parameter.getKey(), parameter.getValue());
      }
    }
    if (pageSize > 0) {
      query.setFirstResult(pageNumber * pageSize);
      query.setMaxResults(pageSize);
    }

    List<T> records = query.list();
    QueryResult<T> queryResult = new QueryResult<T>();
    queryResult.setRecords(records);
    queryResult.setPage(pageNumber);
    queryResult.setPageSize(pageSize);
    queryResult.setRecordCount(records.size());

    if (queryResult.getPageSize() <= 0) {
      queryResult.setRecordCount(queryResult.getRecordCount());
      queryResult.setPageCount(queryResult.getRecords().isEmpty() ? 0 : 1);
    } else {
      query = session.createQuery(sql.toCountSQL());
      for (Map.Entry<String, Object> parameter : sql.getParameters().entrySet()) {
        if (parameter.getValue() instanceof Collection) {
          query.setParameterList(parameter.getKey(), (Collection) parameter.getValue());
        } else if (parameter.getValue() instanceof Object[]) {
          query.setParameterList(parameter.getKey(), (Object[]) parameter.getValue());
        } else {
          query.setParameter(parameter.getKey(), parameter.getValue());
        }
      }
      List<Long> list = query.list();
      int count = list.isEmpty() ? 0 : list.get(0).intValue();

      queryResult.setRecordCount(count);
      int pageCount = count / queryResult.getPageSize();
      if (count % queryResult.getPageSize() != 0) {
        pageCount++;
      }
      queryResult.setPageCount(pageCount);
    }
    return queryResult;
  }
}
